#include "Framework/Win32/Win32Framework.h"
#include "Framework/Win32/Win32Kernel.h"
#include "Framework/App.h"

#include "Framework/Win32/glut/glut.h"

#include <cassert>

namespace Orca {

	//--------------------------------------------------------------------------
	Win32Framework *Win32Framework::msInst = NULL;

	//--------------------------------------------------------------------------
	void Win32Framework::_glutIdle(void) {

		if(msInst) {

			glutPostRedisplay();
		}
	}

	//--------------------------------------------------------------------------
	void Win32Framework::_glutDisplay(void) {

		if(msInst) {

			msInst->mKernel->step();
			msInst->mApp->step(1.0f);
		}

		glutSwapBuffers();
	}

	//--------------------------------------------------------------------------
	void Win32Framework::_glutReshape(int width, int height) {

		if(msInst) {

			msInst->mApp->notifyResChanged( (uint32)width, (uint32)height );
		}
	}

	//--------------------------------------------------------------------------
	void Win32Framework::_glutKeyboard(uint8 c, int x, int y) {

		if(msInst) {

			msInst->mApp->notifyKeyboardEvent(c);
		}
	}

	//--------------------------------------------------------------------------
	void Win32Framework::_glutMouse(int button, int state, int x, int y) {

		int btnMapping[3];
		btnMapping[GLUT_LEFT_BUTTON]	= IApp::LEFT_BUTTON;
		btnMapping[GLUT_MIDDLE_BUTTON]	= IApp::MIDDLE_BUTTON;
		btnMapping[GLUT_RIGHT_BUTTON]	= IApp::RIGHT_BUTTON;

		if(msInst) {

			if(button < 3) {
				msInst->mApp->notifyMouseButtonEvent(
					 (IApp::MOUSE_BUTTON)btnMapping[button]
					,(GLUT_DOWN == state)
					,x, y);
			}
		}
	}

	//--------------------------------------------------------------------------
	void Win32Framework::_glutMouseMotion(int x, int y) {

		if(msInst) {

			msInst->mApp->notifyMouseMotionEvent(x, y);
		}
	}

	//--------------------------------------------------------------------------
	void Win32Framework::_glutExit(void) {

		if(msInst) {

			delete msInst;
		}
	}

	//--------------------------------------------------------------------------
	Win32Framework::Win32Framework() {

		msInst = this;
		mKernel = new Win32Kernel;
	}

	//--------------------------------------------------------------------------
	Win32Framework::~Win32Framework() {

		msInst = NULL;

		mApp->shutdown();
		delete mApp;

		mKernel->shutdown();
		delete mKernel;
	}

	//--------------------------------------------------------------------------
	bool Win32Framework::run(IApp *app, int argc, char** argv) {

		assert(app);
		mApp = app;

		uint32 w, h;
		Str title;

		mApp->getInitRes(w, h);
		mApp->getAppTitle(title);

		glutInitWindowSize( (int)w, (int)h );
		glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH | GLUT_STENCIL);
		glutInit(&argc, argv);
		glutCreateWindow( title.c_str() );
		
		glutReshapeFunc			( _glutReshape );
		glutDisplayFunc			( _glutDisplay );
		glutKeyboardFunc		( _glutKeyboard );
		glutMouseFunc			( _glutMouse );
		glutMotionFunc			( _glutMouseMotion );
		glutPassiveMotionFunc	( _glutMouseMotion );
		glutIdleFunc			( _glutIdle );
		::atexit				(_glutExit);

		mKernel->registerDefaultModules();
		mApp->registerPluginModules();

		mKernel->startup();
		mApp->startup(this);

		glutMainLoop();

		return true;
	}

	//--------------------------------------------------------------------------
	void Win32Framework::exit() {
		
		::exit(0);
	}

	//--------------------------------------------------------------------------
}